﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.Verifications;

namespace Pixysoft.Framework.Sockets
{
    class FastBuffer
    {
        public static readonly int SIZE_SHORT = sizeof(short);
        public static readonly int SIZE_INT16 = sizeof(Int16);
        public static readonly int SIZE_INT32 = sizeof(Int32);
        public static readonly int SIZE_INT64 = sizeof(Int64);
        public static readonly int SIZE_LONG = sizeof(long);
        public static readonly int SIZE_FLOAT = sizeof(float);
        public static readonly int SIZE_DOUBLE = sizeof(double);

        private byte[] _data;//缓存
        private int _position;//当前缓存指针位置
        private int _limit;//有效数据大小
        private int _capacity;//缓存总大小
        private bool isAutoExtend = true;


        /// <summary>
        /// 分配新可用空间
        /// </summary>
        /// <param name="size"></param>
        /// <returns></returns>
        public static FastBuffer Allocate(int size)
        {
            FastBuffer buffer = new FastBuffer();
            buffer._data = new byte[size];
            buffer.Capacity = size;
            return buffer;
        }

        /// <summary>
        /// 当前数据包裹为对象
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public static FastBuffer Wrap(byte[] data)
        {
            FastBuffer buffer = new FastBuffer();
            buffer._data = data;
            buffer.Capacity = data.Length;
            return buffer;
        }

        /// <summary>
        /// 获取剩余可用空间
        /// </summary>
        public long Remaining
        {
            get
            {
                return _limit - _position;
            }
        }

        /// <summary>
        /// 设置当前位置，如果超出limit，则调整limit
        /// </summary>
        public int Position
        {
            get
            {
                return _position;
            }
            set
            {
                if (value > _capacity)
                    throw Exceptions.UnexpectedResultException("position exceed capacity");

                _position = value;

                if (_position > Limit)
                {
                    Limit = _position;
                }
            }
        }

        /// <summary>
        /// 设置分配空间，同时设置当前位置
        /// </summary>
        public int Limit
        {
            get
            {
                return _limit;
            }
            set
            {
                if (value > _capacity)
                    throw Exceptions.UnexpectedResultException("limit exceed capacity");

                if (value < _position)
                    _position = value;

                _limit = value;
            }
        }

        /// <summary>
        /// 设置可用容量，同时重置limit
        /// </summary>
        public int Capacity
        {
            get
            {
                return _capacity;
            }
            set
            {
                if (value < _limit)
                    _limit = value;

                if (value < _position)
                    _position = value;

                _capacity = value;
            }
        }

        /// <summary>
        /// 删除当前位置之后的内容，并位置重新清0
        /// </summary>
        public void Flip()
        {
            Limit = Position;
            Position = 0;
        }

        /// <summary>
        /// 位置清0
        /// </summary>
        public void Rewind()
        {
            Position = 0;
        }

        /// <summary>
        /// 位置清0
        /// 有效空间=最大空间
        /// </summary>
        public void Clear()
        {
            Position = 0;
            Limit = Capacity;
        }

        public void Reset()
        {
            Position = 0;
            Limit = 0;
        }

        public void Free()
        {
            _data = null;
            Position = 0;
            Limit = 0;
            Capacity = 0;
        }

        /// <summary>
        /// 返回包含未用空间的缓存
        /// </summary>
        /// <returns></returns>
        public byte[] ToAllBytes()
        {
            return _data;
        }

        /// <summary>
        /// 返回已用缓存
        /// </summary>
        /// <returns></returns>
        public byte[] CopyAvaliableBytes()
        {
            byte[] ret = new byte[_limit];

            Array.Copy(_data, 0, ret, 0, _limit);

            return ret;
        }




        public byte ReadByte()
        {
            return Buffer.GetByte(_data, Position++);
        }

        public byte[] ReadBytes(long length)
        {
            byte[] ret = new byte[length];
            for (int i = 0; i < length; i++)
            {
                ret[i] = Buffer.GetByte(_data, Position++);
            }
            return ret;
        }

        public short ReadShort()
        {
            short ret = BitConverter.ToInt16(_data, Position);
            Position += SIZE_SHORT;
            return ret;
        }

        public short ReadInt16()
        {
            short ret = BitConverter.ToInt16(_data, Position);
            Position += SIZE_INT16;
            return ret;
        }

        public int ReadInt32()
        {
            int ret = BitConverter.ToInt32(_data, Position);
            Position += SIZE_INT32;
            return ret;
        }

        public long ReadInt64()
        {
            long ret = BitConverter.ToInt64(_data, Position);
            Position += SIZE_INT64;
            return ret;
        }

        public long ReadLong()
        {
            long ret = BitConverter.ToInt64(_data, Position);
            Position += SIZE_LONG;
            return ret;
        }

        public float ReadFloat()
        {
            float ret = BitConverter.ToSingle(_data, Position);
            Position += SIZE_FLOAT;
            return ret;
        }

        public double ReadDouble()
        {
            double ret = BitConverter.ToDouble(_data, Position);
            Position += SIZE_DOUBLE;
            return ret;
        }



        public void WriteByte(byte _byte)
        {
            if (_position + 1 > this.Capacity)
            {
                if (isAutoExtend)
                {
                    byte[] dest = new byte[_capacity + _capacity / 2 + 1];
                    Buffer.BlockCopy(_data, 0, dest, 0, _data.Length);
                }
                else
                    throw Exceptions.UnexpectedResultException("not auto extend and exceed capacity");
            }
            Buffer.SetByte(_data, Position++, _byte);
        }

        public void WriteBytes(byte[] data, int start, int length)
        {
            if (_position + length > this.Capacity)
            {
                if (isAutoExtend)
                {
                    _capacity = _capacity + _capacity / 2 + length;

                    byte[] dest = new byte[_capacity];

                    Buffer.BlockCopy(_data, 0, dest, 0, _data.Length);

                    _data = dest;
                }
                else
                    throw Exceptions.UnexpectedResultException("not auto extend and exceed capacity");
            }
            for (int i = start; i < start + length; i++)
            {
                Buffer.SetByte(_data, Position++, data[i]);
            }
        }

        public void WriteBytes(byte[] data)
        {
            WriteBytes(data, 0, data.Length);
        }

        public void WriteShort(short data)
        {
            WriteBytes(BitConverter.GetBytes(data));
        }

        public void WriteInt16(short data)
        {
            WriteBytes(BitConverter.GetBytes(data));
        }

        public void WriteInt32(int data)
        {
            WriteBytes(BitConverter.GetBytes(data));
        }

        public void WriteInt64(long data)
        {
            WriteBytes(BitConverter.GetBytes(data));
        }

        public void WriteLong(long data)
        {
            WriteBytes(BitConverter.GetBytes(data));
        }

        public void WriteFloat(float data)
        {
            WriteBytes(BitConverter.GetBytes(data));
        }

        public void WriteDouble(double data)
        {
            WriteBytes(BitConverter.GetBytes(data));
        }

        public void Append(byte[] data, int start, int length)
        {
            if (_position + length > this._capacity)
            {
                _capacity = _capacity + _capacity / 2 + data.Length;

                byte[] dest = new byte[_capacity];

                Buffer.BlockCopy(_data, 0, dest, 0, _data.Length);

                _data = dest;
            }

            WriteBytes(data, start, length);
        }

        public bool AutoExtend
        {
            get
            {
                return isAutoExtend;
            }
            set
            {
                isAutoExtend = true;
            }
        }
    }
}
